package executor

import (
	"context"
	"net/http"
	"strings"

	"github.com/glennliao/apijson-go/action"
	"github.com/glennliao/apijson-go/consts"
	"github.com/glennliao/apijson-go/model"
	"github.com/glennliao/apijson-go/util"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/util/gconv"
)

type C操作执行器 struct {
	S数据库解析器 S数据库解析器
}

func (执行器 *C操作执行器) Z执行(ctx context.Context, 请求 action.C操作执行请求) (返回 model.Map, 错误 error) {
	switch 请求.F方法 {
	case http.MethodPost:
		return 执行器.C插入(ctx, 请求.B表名, 请求.S数据)
	case http.MethodPut:
		for i := range 请求.S数据 {
			返回, 错误 = 执行器.G更新(ctx, 请求.B表名, 请求.S数据[i], 请求.T条件[i])
			if 错误 != nil {
				break
			}
		}
		if 错误 != nil {
			返回 = model.Map{
				"code": 200,
			}
		}
		return 返回, 错误

	case http.MethodDelete:
		for i := range 请求.S数据 {
			返回, 错误 = 执行器.S删除(ctx, 请求.B表名, 请求.T条件[i])
			if 错误 != nil {
				break
			}
		}
		if 错误 != nil {
			返回 = model.Map{
				"code": 200,
			}
		}
		return 返回, 错误
	}
	return nil, consts.X新建方法不支持错误(请求.F方法)
}

func (执行器 *C操作执行器) C插入(ctx context.Context, 表名 string, 数据 []model.Map) (返回 model.Map, 错误 error) {
	结果, 错误 := 执行器.S数据库解析器(ctx).Insert(ctx, 表名, 数据)
	if 错误 != nil {
		return nil, 错误
	}
	ID, 错误 := 结果.LastInsertId()
	if 错误 != nil {
		return nil, 错误
	}

	影响行数, 错误 := 结果.RowsAffected()

	返回 = model.Map{
		"code":  200,
		"count": 影响行数,
		"id":    ID,
	}

	return 返回, nil
}

func (执行器 *C操作执行器) G更新(ctx context.Context, 表名 string, 数据 model.Map, 条件 model.Map) (返回 model.Map, 错误 error) {
	模型 := 执行器.S数据库解析器(ctx).Model(表名).Ctx(ctx)

	for 键, 值 := range 条件 {
		if strings.HasSuffix(键, consts.C操作符包含) {
			if 字符串值, 是字符串 := 值.(string); 是字符串 {
				if 字符串值 == "" {
					return nil, consts.X新建请求验证错误("where的值不能为空")
				}
			}
			模型 = 模型.WhereIn(键[0:len(键)-2], 值)
			delete(条件, 键)
			continue
		}
		if 键 == consts.Y原始数据 {
			模型 = 模型.Where(值.(map[string][]any))
			delete(条件, 键)
			continue
		}

		if 值 == nil || gconv.String(值) == "" { // 暂只处理字符串为空的情况
			return nil, consts.X新建请求验证错误("where的值不能为空:" + 键)
		}
	}

	for 键, 值 := range 数据 {
		if strings.HasSuffix(键, consts.C操作符加) {
			字段 := util.Y移除后缀(键, consts.C操作符加)
			数据[字段] = &gdb.Counter{
				Field: 字段,
				Value: gconv.Float64(值),
			}
			delete(数据, 键)
			continue
		}
		if strings.HasSuffix(键, consts.C操作符减) {
			字段 := util.Y移除后缀(键, consts.C操作符减)
			数据[字段] = &gdb.Counter{
				Field: 字段,
				Value: -gconv.Float64(值),
			}
			delete(数据, 键)
			continue
		}

		if 数据[键] == nil {
			// 此处目前不允许外部设置null
			delete(数据, 键)
		}
	}

	结果, 错误 := 模型.Where(条件).Update(数据)
	if 错误 != nil {
		return nil, 错误
	}

	影响行数, 错误 := 结果.RowsAffected()
	if 错误 != nil {
		return nil, 错误
	}

	返回 = model.Map{
		"code":  200,
		"count": 影响行数,
	}

	return 返回, 错误
}

func (执行器 *C操作执行器) S删除(ctx context.Context, 表名 string, 条件 model.Map) (返回 model.Map, 错误 error) {
	if len(条件) == 0 {
		return nil, consts.X新建请求验证错误("where的值不能为空")
	}

	模型 := 执行器.S数据库解析器(ctx).Model(表名).Ctx(ctx)

	for 键, 值 := range 条件 {
		if 键 == consts.Y原始数据 {
			模型 = 模型.Where(值)
			continue
		}

		if strings.HasSuffix(键, consts.C操作符包含) {
			模型 = 模型.WhereIn(键[0:len(键)-2], 值)
			delete(条件, 键)
			continue
		}

		if gconv.String(值) == "" || 值 == nil { // 暂只处理字符串为空的情况
			return nil, consts.X新建请求验证错误("where的值不能为空:" + 键)
		}

		模型 = 模型.Where(键, 值)
	}

	结果, 错误 := 模型.Delete()
	if 错误 != nil {
		return nil, 错误
	}

	影响行数, 错误 := 结果.RowsAffected()

	if 错误 != nil {
		return nil, 错误
	}

	返回 = model.Map{
		"code":  200,
		"count": 影响行数,
	}

	return 返回, 错误
}
